package encrypt

import (
	"bytes"
	"crypto"
	"crypto/aes"
	"crypto/cipher"
	"crypto/hmac"
	"crypto/md5"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/hex"
	"encoding/pem"
	"errors"
	"fmt"
	"github.com/farmerx/gorsa"
	"sort"
)

// GenerateSortMapSpliceString 生成形参排序并拼接的字符串
func GenerateSortMapSpliceString(params map[string]any, connChar string) string {
	var keys []string
	for k, _ := range params {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	var signStr string
	frontHave := false
	for _, key := range keys {
		if params[key] != "" {
			if frontHave {
				signStr += connChar
			}
			signStr += key + "=" + fmt.Sprint(params[key])
			frontHave = true
		}
	}
	return signStr
}

// MD5Encrypt md5加密-对称-不可逆 摘要算法
func MD5Encrypt(in string) string {
	m := md5.New()
	m.Write([]byte(in))
	return hex.EncodeToString(m.Sum(nil))
}

// RSAEncrypt rsa-非对称-可逆
func RSAEncrypt(signStr string, privateKey string, hash crypto.Hash) (sign []byte, err error) {
	block, _ := pem.Decode([]byte(privateKey))
	if block == nil {
		err = errors.New("decode private key failed")
		return
	}

	privt, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		panic(err)
		return
	}

	h := hash.New()
	h.Write([]byte(signStr))
	sign, err = rsa.SignPKCS1v15(rand.Reader, privt.(*rsa.PrivateKey), hash, h.Sum(nil))
	return
}

func RSAEncryptUnHash(signStr string, privateKey string) (sign []byte, err error) {
	if err = gorsa.RSA.SetPrivateKey(privateKey); err != nil {
		return
	}
	sign, err = gorsa.RSA.PriKeyENCTYPT([]byte(signStr))
	return
}

// AESEncrypt aes 对称-可逆
func AESEncrypt(key, iv string, in []byte) (sign []byte, err error) {
	encryptBytes := in
	block, err := aes.NewCipher([]byte(key))
	if err != nil {
		return sign, err
	}
	blockSize := block.BlockSize()
	encryptBytes = pkcs5Padding(encryptBytes, blockSize)
	blockMode := cipher.NewCBCEncrypter(block, []byte(iv))
	encrypted := make([]byte, len(encryptBytes))
	blockMode.CryptBlocks(encrypted, encryptBytes)
	return encrypted, nil
}

func pkcs5Padding(cipherText []byte, blockSize int) []byte {
	padding := blockSize - len(cipherText)%blockSize
	padText := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(cipherText, padText...)
}

// HmacEncrypt hmac 秘钥加密-摘要算法
func HmacEncrypt(hash crypto.Hash, key, instr []byte) string {
	h := hmac.New(hash.New, key)
	h.Write(instr)
	return base64.URLEncoding.EncodeToString(h.Sum(nil))
}
